package com.web.controller.common;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.common.annotation.EnumValid;
import com.common.apiresult.CommonResult;
import com.common.apiresult.ResultCode;
import com.common.constant.RedisConstant;
import com.common.domain.dto.AddUserDTO;
import com.common.domain.dto.UserUpdateInfoDTO;
import com.common.enums.FormOperateEnum;
import com.common.exception.BusinessException;
import com.common.utils.ImageUtil;
import com.common.utils.RedisUtil;
import com.google.code.kaptcha.Producer;
import com.service.serviceInterface.*;
import com.system.entity.*;
import com.web.entity.dto.UserLoginDTO;
import com.web.entity.dto.UserRegisterDTO;
import com.web.entity.dto.UserUpdatePwdDTO;
import com.web.entity.dto.UserUpdatePwdDTO2;
import com.web.entity.vo.LoginUserInfoVO;
import com.web.entity.vo.UserProfileVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author liuxuhuang
 * @date 2023年03月30日 21:03
 * @desc 用户控制器
 */
@RestController
@RequestMapping(value = "/auth")
@Api(value = "UserController", tags = "用户登录，注册,验证码")
@Slf4j
public class UserController {
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private ImageUtil imageUtil;
    @Resource
    private UserService userService;
    @Resource
    private RoleService roleService;
    @Resource
    private StudentInfoService studentInfoService;
    @Resource
    private WorkInfoService workInfoService;
    @Resource
    private GuestInfoService guestInfoService;
    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Resource
    private Producer producer;

    @ApiOperation(value = "用户注册")
    @PostMapping(value = "/user/register")
    public CommonResult userRegister(@RequestBody @Validated UserRegisterDTO registerVO) {
        //根据邮箱查询 验证码判断
        String redisCode = (String) redisUtil.get(RedisConstant.REGISTER_FORM_PREFIX + registerVO.getEmail());
        if (StringUtils.isBlank(redisCode) || !registerVO.getCode().equals(redisCode)) {
            log.info("验证码已过期 registerVO={}", registerVO);
            throw new BusinessException("验证码已过期");
        }
        //清除验证码
        redisUtil.del(RedisConstant.REGISTER_FORM_PREFIX + registerVO.getEmail());
        if (!registerVO.getPassword().equals(registerVO.getRePassword())) {
            log.info("两次密码不一致 registerVO={}", registerVO);
            throw new BusinessException("两次密码不一致");
        }
        //注册
        AddUserDTO addUserDTO = new AddUserDTO();
        addUserDTO.setEmail(registerVO.getEmail()).setPassword(bCryptPasswordEncoder.encode(registerVO.getPassword())).setUsername(registerVO.getEmail());
        userService.register(addUserDTO);
        return CommonResult.success();
    }

    @ApiOperation(value = "获取表单验证码")
    @GetMapping(value = "/user/getKaptchaCode")
    public CommonResult getKaptchaImage(@RequestParam("operate") @NotBlank(message = "表单操作不能为空")
                                        @EnumValid(target = FormOperateEnum.class, validField = "getName", message = "表单操作类型错误") String operate,
                                        @RequestParam("email") String email) throws IOException {
        String text = producer.createText();
        log.info("产生验证码：{}", text);
        BufferedImage image = producer.createImage(text);
        if (operate.equals(FormOperateEnum.LOGIN.getCode())) {
            String s = imageUtil.convertBufferedImageToBase64(image);
            String randomUUID = IdUtil.randomUUID();
            redisUtil.set(RedisConstant.LOGIN_FORM_PREFIX + randomUUID, text, 300);
            return CommonResult.success(randomUUID, s);
        } else if (operate.equals(FormOperateEnum.ERGISTER.getCode())) {
            if (StringUtils.isBlank(email)) {
                return CommonResult.failed(ResultCode.USERNAMENOEXIST);
            }
            userService.sendEmail("高校宿舍管理系统", "注册验证码：" + text, email);
            redisUtil.set(RedisConstant.REGISTER_FORM_PREFIX + email, text, 300);
            return CommonResult.success();
        } else if (operate.equals(FormOperateEnum.RESETPWD.getCode())) {
            if (StringUtils.isBlank(email)) {
                return CommonResult.failed(ResultCode.USERNAMENOEXIST);
            }
            userService.sendEmail("高校宿舍管理系统", "重置密码验证码：" + text, email);
            redisUtil.set(RedisConstant.UPDATEPWD_FORM_PREFIX + email, text, 300);
            return CommonResult.success();
        }
        return CommonResult.failed();
    }

    @ApiOperation(value = "用户登录")
    @PostMapping(value = "/user/login")
    public CommonResult userLogin(@RequestBody @Validated UserLoginDTO userLoginDTO) {
        log.info("userForm={}" + userLoginDTO);
        String keyValue = (String) redisUtil.get(RedisConstant.LOGIN_FORM_PREFIX + userLoginDTO.getFormKey());
        if (StringUtils.isBlank(keyValue) || !keyValue.equals(userLoginDTO.getCode())) {
            log.info("验证码已过期 registerVO={}", userLoginDTO);
            throw new BusinessException("验证码已过期");
        }
        redisUtil.del(RedisConstant.LOGIN_FORM_PREFIX + userLoginDTO.getFormKey());
        String login = userService.login(userLoginDTO.getUsername(), userLoginDTO.getPassword());
        return CommonResult.success(login);
    }

    @ApiOperation(value = "用户退出")
    @PostMapping(value = "/user/layout")
    public CommonResult userLogout() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        redisUtil.del(RedisConstant.LOGIN_USER_PREFIX + loginUser.getUser().getId());
        return CommonResult.success();
    }

    @ApiOperation(value = "用户修改密码")
    @PutMapping(value = "/user/updatePwd")
    public CommonResult userUpdatePwd(@RequestBody @Validated UserUpdatePwdDTO dto) {
        log.info("userForm={}" + dto);
        String keyValue = (String) redisUtil.get(RedisConstant.UPDATEPWD_FORM_PREFIX + dto.getEmail());
        if (StringUtils.isBlank(keyValue) || !keyValue.equals(dto.getCode())) {
            log.info("验证码已过期 UserUpdatePwdVO={}", dto);
            throw new BusinessException("验证码已过期");
        }
        redisUtil.del(RedisConstant.UPDATEPWD_FORM_PREFIX + dto.getEmail());
        userService.updatePwd(dto.getEmail(), dto.getPassword());
        return CommonResult.success();
    }

    @ApiOperation(value = "用户修改密码——已登录状态")
    @PutMapping(value = "/user/resetPwd")
    public CommonResult userUpdatePwd2(@RequestBody @Validated UserUpdatePwdDTO2 dto) {
        log.info("updatePwdDTO2={}" + dto);
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        if (!bCryptPasswordEncoder.matches(dto.getOldPassword(), loginUser.getPassword())) {
            return CommonResult.failed("旧密码错误");
        }
        userService.updatePwd(loginUser.getUser().getEmail(), dto.getNewPassword());
        return CommonResult.success();
    }

    /**
     * 只返回用户名和角色
     *
     * @return
     */
    @ApiOperation(value = "获取用户信息")
    @GetMapping(value = "/user/info")
    public CommonResult getUserInfo() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        LoginUserInfoVO infoVO = new LoginUserInfoVO();
        infoVO.setUserName(loginUser.getUser().getEmail()).setRoles(loginUser.getRoles());
        return CommonResult.success(infoVO);
    }

    @ApiOperation(value = "获取基本用户信息")
    @GetMapping(value = "/user/profile")
    public CommonResult getUserProfile() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        UserProfileVO vo = new UserProfileVO();
        vo.setUserName(loginUser.getUsername()).setRoles(loginUser.getRoles())
                .setEmail(loginUser.getUser().getEmail()).setRegisterTime(loginUser.getUser().getRegister());
        List<String> strings = loginUser.getRoles().stream().map(i -> roleService.getOne(new LambdaQueryWrapper<Role>().eq(Role::getName, i))).map(Role::getDescription).collect(Collectors.toList());
        vo.setRoles(strings);
        /**
         * 根据不同角色，查询不同的表返回用户信息
         */
        if (loginUser.getRoles().contains("student")) {
            StudentInfo one = studentInfoService.getOne(new LambdaQueryWrapper<StudentInfo>().eq(StudentInfo::getUserId, loginUser.getUser().getId()));
            vo.setPhone(one.getPhone()).setNickName(one.getName()).setSex(one.getSex());
        } else if (loginUser.getRoles().stream().anyMatch(i -> Arrays.asList("dormManagement", "plumber", "schoolManagement").contains(i))) {
            WorkInfo one = workInfoService.getOne(new LambdaQueryWrapper<WorkInfo>().eq(WorkInfo::getUserId, loginUser.getUser().getId()));
            vo.setPhone(one.getPhone()).setNickName(one.getName()).setSex(one.getSex());
        } else if (loginUser.getRoles().contains("guest")) {
            GuestInfo one = guestInfoService.getOne(new LambdaQueryWrapper<GuestInfo>().eq(GuestInfo::getUserId, loginUser.getUser().getId()));
            vo.setPhone(one.getPhone()).setNickName(one.getName()).setSex(one.getSex());
        }
        return CommonResult.success(vo);
    }

    @ApiOperation(value = "更新用户信息")
    @PutMapping(value = "/user/profile")
    public CommonResult updateUserProfile(@RequestBody @Validated UserUpdateInfoDTO dto) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        userService.updateInfo(dto, loginUser);
        return CommonResult.success();
    }

    @ApiOperation(value = "判断邮箱是否存在")
    @GetMapping(value = "/user/ifEmailExist")
    public CommonResult ifEmailExist(@RequestParam("email") @NotBlank(message = "邮箱不能为空") @Email String email) {
        log.info("email={}" + email);
        int count = userService.count(new LambdaQueryWrapper<User>().eq(User::getEmail, email));
        if (count >= 1) {
            log.info("邮箱已存在 email={}", email);
            throw new BusinessException("邮箱已存在");
        }
        return CommonResult.success();
    }
}
